package com.yyplatform.admin.platform.role.service.impl;

import java.util.List;
import java.util.stream.Collectors;

import org.assertj.core.util.Sets;
import org.modelmapper.ModelMapper;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.yyplatform.admin.platform.role.model.dto.SysMenuDTO;
import com.yyplatform.admin.platform.role.model.dto.SysRoleDTO;
import com.yyplatform.admin.platform.role.model.dto.SysRoleFormDTO;
import com.yyplatform.admin.platform.role.model.dto.SysRoleMenuDTO;
import com.yyplatform.admin.platform.role.model.dto.SysRoleMenuFormDTO;
import com.yyplatform.admin.platform.role.model.dto.SysRoleQueryDTO;
import com.yyplatform.admin.platform.role.model.entity.SysMenuEntity;
import com.yyplatform.admin.platform.role.model.entity.SysRoleEntity;
import com.yyplatform.admin.platform.role.model.entity.SysRoleMenuEntity;
import com.yyplatform.admin.platform.role.model.entity.SysUserRoleEntity;
import com.yyplatform.admin.platform.role.repository.SysMenuRepository;
import com.yyplatform.admin.platform.role.repository.SysRoleMenuRepository;
import com.yyplatform.admin.platform.role.repository.SysRoleRepository;
import com.yyplatform.admin.platform.role.repository.SysUserRoleRepository;
import com.yyplatform.admin.platform.role.service.SysRoleService;
import com.yyplatform.admin.infra.exception.ErrorCode;
import com.yyplatform.admin.infra.exception.ServiceException;
import com.yyplatform.admin.infra.utils.DateUtils;
import com.yyplatform.admin.infra.utils.TreeUtils;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * Created on 2024-09-14
 */
@Service
@Slf4j
@AllArgsConstructor
public class SysRoleServiceImpl implements SysRoleService {

    private SysRoleRepository sysRoleRepository;
    private SysUserRoleRepository sysUserRoleRepository;
    private SysRoleMenuRepository sysRoleMenuRepository;
    private SysMenuRepository sysMenuRepository;
    private ModelMapper modelMapper;


    @Override
    public Page<SysRoleDTO> query(SysRoleQueryDTO pageQueryDTO) {

        Page<SysRoleEntity> entityPage =
                sysRoleRepository.findPage(pageQueryDTO.getName(), pageQueryDTO.getCode(), pageQueryDTO.getEnabled(),
                        DateUtils.getBeginDate(pageQueryDTO.getBeginStr()),
                        DateUtils.getEndDate(pageQueryDTO.getEndStr()),
                        pageQueryDTO.getPageRequestOrderByOrderNumDesc());

        List<SysRoleDTO> lst = entityPage.getContent().stream().map(e -> modelMapper.map(e, SysRoleDTO.class))
                .collect(Collectors.toList());

        return new PageImpl<>(lst, entityPage.getPageable(), entityPage.getTotalElements());
    }


    @Override
    public SysRoleDTO get(Long id) {
        SysRoleEntity sysRoleEntity = sysRoleRepository.getReferenceById(id);
        return modelMapper.map(sysRoleEntity, SysRoleDTO.class);
    }


    @Override
    public void save(SysRoleFormDTO formDTO) {
        SysRoleEntity sysRoleEntity = modelMapper.map(formDTO, SysRoleEntity.class);

        sysRoleEntity.setDataScope(0);
        sysRoleRepository.save(sysRoleEntity);
    }


    @Override
    public void update(SysRoleFormDTO formDTO) {
        SysRoleEntity sysRoleEntity = sysRoleRepository.getReferenceById(formDTO.getId());
        sysRoleEntity.setCode(formDTO.getCode());
        sysRoleEntity.setName(formDTO.getName());
        sysRoleEntity.setRemark(formDTO.getRemark());
        sysRoleEntity.setEnabled(formDTO.getEnabled());
        sysRoleEntity.setOrderNum(formDTO.getOrderNum());


        sysRoleRepository.save(sysRoleEntity);
    }

    @Override
    public void delete(Long id) {
        List<SysUserRoleEntity> sysUserRoleEntityList = sysUserRoleRepository.findByRoleId(id);
        if (sysUserRoleEntityList != null && !sysUserRoleEntityList.isEmpty()) {
            throw ServiceException.of(ErrorCode.DELETE_DATA_ERROR_IN_USE);
        }

        List<SysRoleMenuEntity> sysRoleMenuEntityList = sysRoleMenuRepository.findByRoleIdIn(Sets.set(id));
        if (sysRoleMenuEntityList != null && !sysRoleMenuEntityList.isEmpty()) {
            throw ServiceException.of(ErrorCode.DELETE_DATA_ERROR_IN_USE);
        }

        sysRoleRepository.deleteById(id);
    }

    @Override
    public SysRoleMenuDTO queryMenu(Long id) {
        List<SysMenuEntity> dblist = sysMenuRepository.findAll();

        List<SysMenuDTO> dtoList = dblist.stream().map(e -> modelMapper.map(e, SysMenuDTO.class)).toList();


        dtoList = TreeUtils.build(dtoList, 0L);

        SysRoleMenuDTO sysRoleMenuDTO = new SysRoleMenuDTO();

        sysRoleMenuDTO.setTreeData(dtoList);

        List<SysRoleMenuEntity> sysRoleMenuEntityList = sysRoleMenuRepository.findByRoleIdIn(Sets.set(id));
        List<Long> menuIds = sysRoleMenuEntityList.stream().map(SysRoleMenuEntity::getMenuId).toList();

        sysRoleMenuDTO.setCheckedTreeNode(menuIds);

        return sysRoleMenuDTO;
    }

    @Transactional
    @Override
    public void saveMenu(SysRoleMenuFormDTO formDTO) {
        List<SysRoleMenuEntity> sysRoleMenuEntityList = sysRoleMenuRepository.findByRoleId(formDTO.getRoleId());
        sysRoleMenuRepository.deleteAll(sysRoleMenuEntityList);

        if (formDTO.getMenuIds() != null && !formDTO.getMenuIds().isEmpty()) {
            formDTO.getMenuIds().forEach(menuId -> {
                SysRoleMenuEntity entity = new SysRoleMenuEntity();
                entity.setMenuId(menuId);
                entity.setRoleId(formDTO.getRoleId());
                sysRoleMenuRepository.save(entity);
            });
        }

    }

    @Override
    public List<SysRoleDTO> getOptions() {
        List<SysRoleEntity> roleEntityList = sysRoleRepository.findAll();
        return roleEntityList.stream().map(e -> modelMapper.map(e, SysRoleDTO.class)).toList();
    }
}
